package client;

import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

public class Client implements Serializable {
    
     Integer AUTHENTIFICATION   =1;
     Integer INSCRIPTION        =2;
     Integer ENVOYEMESSAGESALON =3;
     Integer ENOYEMESSAGECLIENT =4;
     Integer AJOUTERCONTACT     =5;
     Integer SUPPRIMERCONTACT   =6;
     Integer FERMETURECONNEXION =7;
     
     Integer ECHEC_AUTHENTIFICATION  =0;
     Integer SUCCES_AUTHENTIFICATION =1;
    
    public BoiteDialogueGenerique boiteDialogue;
    DataInputStream               entree;        // float de sortie pour données typées
    public FenetreConnexion       fenetreConnexion;
    public FenetreConversation    fenetreConversation;
    public FenetreInscription     fenetreInscription;
    InputStream                   in;            // pour récupérer le flot d'entrée de la socket
    private String                nomServeur;    // nom du serveur auquel le client est connecté
    OutputStream                  out;           // pour récupérer le flot de sortie de la socket

    // Attributs
    private int                   portServeur;    // numero de port du serveur
    public String                 pseudoClient;
    public String                 pseudo;
    public String                 nom;
    public String                 prenom;
    public String                 email;
    public String                 motDePasse;
    public String                 titre;
    public String                 contenu;
             
    Socket                        socketTransfert;
    DataOutputStream              sortie;         // float d'entrée pour données typées
    public TraitementConversation traitementConversations;
    public ConcurrentHashMap<String,Salon> salons;
    public ConcurrentHashMap<String,Utilisateur> contacts;

    // Constructeur
    public Client() {
        fenetreConnexion    = new FenetreConnexion(this);
        fenetreConversation = null;
        fenetreInscription  = new FenetreInscription(this);
        boiteDialogue       = new BoiteDialogueGenerique(this);
        this.fenetreConnexion.setVisible(true);
        this.fenetreInscription.setVisible(false);
        this.boiteDialogue.setVisible(false);
        salons = new  ConcurrentHashMap<String,Salon>();
        contacts = new  ConcurrentHashMap<String,Utilisateur>();
    }

    // Main
    public static void main(String[] args) {
            Client client = new Client();
            client.ouvertureConnexionTCP();
    }

    // Connexion
    public void connexion(String pseudo, String motDePasse, String nomServeur, String NumeroPort) {
        try {
            this.setNomServeur(nomServeur);
            this.setPortServeur(Integer.parseInt(NumeroPort));
            this.setMotDePasse(motDePasse);
            this.setPseudo(pseudo);
            this.afficheInfosServeur();       // affiche l'@ IP du serveur
            this.authentification();          // Authentification du client avec son pseudo + mot de passe 
            
            System.out.println("Salons : ");
            for(String key : this.salons.keySet()){
                System.out.println(this.salons.get(key).getTitre());
            }   
            System.out.println("Contacts : ");
            for(String key : this.contacts.keySet()){
                System.out.println(this.contacts.get(key).getPseudo());
            }
            this.traiterConversations();      // donc traitement de la conversation si la connexion est bien établi
        } catch (NumberFormatException e) {    // exception levée lors de la convertion du numero de port chaine=>entier dans la classe Integer méthode parseInt()
            this.afficherMessage("Erreur : Le numero de port donné est trop grand");
        }
    }
    
    public String[] listeDesSalons(){
        ArrayList<String> titreSalons = new ArrayList<String>();
        if(this.salons!=null){
            for(String key : this.salons.keySet()){
               titreSalons.add(this.salons.get(key).getTitre());
            }  
            System.out.println("Liste des salons envoyés : ");
            String salonss[] = new String[titreSalons.size()];
            for(int i=0;i<titreSalons.size();i++){
                salonss[i]=titreSalons.get(i);
                System.out.println(salonss[i]);
            }
            return salonss;
        }else{
            return null;
        }
    }
    
     public String[] listeDesContacts(){
        ArrayList<String> pseudoContacts = new ArrayList<String>();
        if(this.contacts!=null){
            for(String key : this.contacts.keySet()){
               pseudoContacts.add(this.contacts.get(key).getPseudo());
            }  
            System.out.println("Liste des Contacts envoyés : ");
            String contactss[] = new String[pseudoContacts.size()];
            for(int i=0;i<pseudoContacts.size();i++){
                contactss[i]=pseudoContacts.get(i);
                System.out.println(contactss[i]);
            }
            return contactss;
        }else{
            return null;
        }
    }

    // Ouverture de la connexion avec le serveur
    public void authentification(){
        try {
            this.sortie.writeInt(AUTHENTIFICATION); // pour que le serveur sache que je veux faire une authentification
            this.sortie.writeUTF(pseudoClient);           // pseudo du client 
            System.out.println("pseudo envoyé = " + pseudoClient);
            int codeAuthentification = this.entree.readInt();// vérification de l'éxistance de l'utilisateur
            System.out.println("code recu = " + codeAuthentification);
            if (codeAuthentification == SUCCES_AUTHENTIFICATION) {
                System.out.println("code : " + codeAuthentification);                
                this.afficherMessage("Bienvenue " + this.pseudoClient);
                
                //lecture des salons et des utilisateurs
                titre = this.entree.readUTF();
                while(!titre.equalsIgnoreCase("finSalons")){
                    contenu = this.entree.readUTF();
                    Salon  s = new Salon(titre,contenu);
                    this.ajouterSalon(titre,s);
                    titre = this.entree.readUTF();
                }
                
                pseudo = this.entree.readUTF();
                while(!pseudo.equalsIgnoreCase("finContacts")){
                    System.out.println("Contact recu : " + pseudo);
                    nom = this.entree.readUTF();
                    prenom = this.entree.readUTF();
                    email = this.entree.readUTF();
                    motDePasse = this.entree.readUTF();
                    Utilisateur u = new Utilisateur(pseudo, nom, prenom, email, motDePasse);
                    this.ajouterUtilisateur(pseudo,u);
                    pseudo = this.entree.readUTF();
                }
            } else {
                this.sortie.writeInt(FERMETURECONNEXION);
                this.afficherMessage("Echec Autentification");
                this.fermetureConnexionTCP();
                System.exit(0);
            }
        } catch (Exception e) {
            this.afficherMessage("Exception levée dans l'authentification 'Client' : " + e.getMessage());
        }
    }
    
      public void ajouterSalon(String titre, Salon s){
              this.salons.put(titre, s);
      }
      
      public void ajouterUtilisateur(String pseudo, Utilisateur u){
          this.contacts.put(pseudo, u);
      }

    // traitement des Conversations aprés ma connexion de l'utilisateur
    public void traiterConversations() {
        fenetreConversation = new FenetreConversation(this);
        fenetreConnexion.setVisible(false);
        fenetreConversation.setVisible(true);
        traitementConversations = new TraitementConversation(this);
        traitementConversations.start();
    }
    

    // inscription d'un nouveau client
    public void inscription(String pseudo, String nom, String prenom, String email, String date){
        try {
            this.sortie.writeInt(INSCRIPTION);
            this.sortie.writeUTF(pseudo);
            this.sortie.writeUTF(nom);
            this.sortie.writeUTF(prenom);
            this.sortie.writeUTF(email);
            this.sortie.writeUTF(date);
            fenetreConnexion.setVisible(true);
            fenetreInscription.setVisible(false);
            this.afficherMessage("Inscription avec succes , bienvenue " + pseudo);
        } catch (Exception e) {
           System.out.println("Exception levée lors de l'inscription 'Client' : " + e.getMessage() + "  " + e.toString() );
        }
    }
  
    public void ouvertureConnexionTCP(){
        try {
            this.socketTransfert = new Socket("localhost", 3000);    // instanciant de la classe Socket pour pouvoir communiquer avec le serveur
            
            try {this.in = this.socketTransfert.getInputStream();} catch (Exception e) {}// instanciant de la classe Socket pour pouvoir communiquer avec le serveur
            this.entree = new DataInputStream(this.in);      // création du flot d'entrée pour données typées
            try {this.out = this.socketTransfert.getOutputStream();} catch (Exception e) {}                         // récupérer le flot de sortie de la socket (dans out)
            this.sortie = new DataOutputStream(this.out);    // création du flot de sortie pour données typées
         } catch (Exception e) {
              this.afficherMessage("Erreur lors de l'ouverture de connexion : " + e.getMessage());
        }
    }
    
    
    public void envoyerMessage( String message, String nomTab,int code){ // envoie d'un message soit a un client soit dans un salon
        try{
                this.sortie.writeInt(code); // ENVOYE_MESSAGE_SALON || ENVOYE_MESSAGE_CLIENT
                this.sortie.writeUTF(this.pseudoClient);
                this.sortie.writeUTF(nomTab);
                this.sortie.writeUTF(message);
        }
        catch(Exception e){
            System.out.println("Exception levée lors de la fermeture de la connexion 'thread - Client' : " + e.getMessage());
        }
    }

   
//Fermeture fenetre
    public void fermetureFenetre(){
        try {
            this.sortie.writeInt(FERMETURECONNEXION);
            this.traitementConversations.fermetureConnexion();
        }catch(Exception e){
            System.out.println("Exception levée lors de la fermeture de la connexion 'thread - Client' : " + e.getMessage());
        }
    }
    
// Affichage de l'@ IP du serveur
    public void afficheInfosServeur() {
        System.out.println("-L'@ IP du serveur en marche : " + socketTransfert.getInetAddress());
    }
    
// Fermeture de la connexion
    public void fermetureConnexionTCP() {
        try {
            socketTransfert.close();
        } catch (Exception e) {
            System.out.println("Exception levée lors de la fermeture de la connexion 'Client' : " + e.getMessage());
        }
    }
    
//Traitement des fenetres
        
    // Afficher la fenetre d'inscription et cacher la fenetre de connexion
    public void afficherFenetreInscription() {
        this.fenetreConnexion.setVisible(false);
        this.fenetreInscription.setVisible(true);
    }

    // Afficher la fenetre de connexion et cacher la fenetre d'inscription
    public void afficherFenetreConnexion() {
        fenetreConnexion.setVisible(true);
        fenetreInscription.setVisible(false);
    }
    
    public void afficherMessage(String message){
        this.boiteDialogue.afficherMessage(message);
    }
    
    
 // Accesseurs & Mutateurs
    public int getPortServeur() {
        return portServeur;
    }

    private void setPortServeur(int portServeur) {
        this.portServeur = portServeur;
    }

    public String getNomServeur() {
        return nomServeur;
    }

    private void setNomServeur(String nomServeur) {
        this.nomServeur = nomServeur;
    }

    public String getPseudo() {
        return this.pseudo;
    }

    private void setPseudo(String pseudo) {
        this.pseudoClient = pseudo;
    }

    public String getMotDePasse() {
        return this.motDePasse;
    }

    private void setMotDePasse(String motDePasse) {
        this.motDePasse = motDePasse;
    }

}    // Fin de la classe Serveur


